package com.hdhere.core.configuration;

import com.hdhere.core.security.shiro.MyDefaultFilterChainManager;
import com.hdhere.core.security.shiro.MyPathMatchingFilterChainResolver;
import com.hdhere.core.security.shiro.MyShiroRealm;
import com.hdhere.core.security.shiro.SecurityDataProvider;
import com.hdhere.core.security.shiro.filter.FormAuthenticationFilter;
import com.hdhere.core.security.shiro.filter.LogoutFilter;
import com.hdhere.core.security.shiro.filter.MyPermsFilter;
import com.hdhere.core.util.SpringUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import javax.servlet.Filter;
import java.util.*;

/**
 * Created by dus on 2018/11/19.
 */
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);


        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        //shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        //shiroFilterFactoryBean.setSuccessUrl("/index");

        //未授权界面 不起作用 通过MyPermsFilter处理
        //shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        //shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        try {
            AbstractShiroFilter shiroFilter = ( (AbstractShiroFilter) shiroFilterFactoryBean.getObject() );
            shiroFilter.setFilterChainResolver(customPathMatchingFilterChainResolver());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return shiroFilterFactoryBean;
    }

    @Bean
    MyDefaultFilterChainManager customDefaultFilterChainManager() {

        MyDefaultFilterChainManager filterChainManager = new MyDefaultFilterChainManager();
        Map<String, Filter> filtersMap = new HashMap<>();
        filtersMap.put("authc", new FormAuthenticationFilter("/login"));
        filtersMap.put("logout", new LogoutFilter());
        MyPermsFilter permsFilter = new MyPermsFilter();
        permsFilter.setLoginUrl("/login");
        filtersMap.put("perms", permsFilter);

        filterChainManager.setCustomFilters(filtersMap);

        Map<String, String> chainMap = new LinkedHashMap<>();
        // 配置不会被拦截的链接 顺序判断
        chainMap.put("/static/**", "anon");
        chainMap.put("/css/**", "anon");
        chainMap.put("/skin/**", "anon");
        chainMap.put("/image/**", "anon");
        chainMap.put("/images/**", "anon");//后台图片
        chainMap.put("/favicon.ico", "anon");
        chainMap.put("/video/**", "anon");
        //chainMap.put("/login", "anon");
        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        chainMap.put("/logout", "logout");

        //<!-- 过滤链定义，从上向下顺序执行，一般将/**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;
        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->

        //添加配置权限 限制粒度细的放上面 坑
        SecurityDataProvider securityDataProvider = SpringUtils.getBean(SecurityDataProvider.class);
        var permissions = securityDataProvider.getPermissionMap();
        chainMap.putAll(permissions);
//        //设置权限格式：
//        chainMap.put("/userInfo/list", "perms[userInfo:view]");
        chainMap.put("/**", "authc");

        filterChainManager.setFilterChainDefinitionMap(chainMap);
        return filterChainManager;
    }

    @Bean
    MyPathMatchingFilterChainResolver customPathMatchingFilterChainResolver() {

        MyDefaultFilterChainManager customDefaultFilterChainManager = customDefaultFilterChainManager();

        MyPathMatchingFilterChainResolver customPathMatchingFilterChainResolver = new MyPathMatchingFilterChainResolver();
        customPathMatchingFilterChainResolver.setCustomDefaultFilterChainManager(customDefaultFilterChainManager);
        return customPathMatchingFilterChainResolver;
    }

    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     * ）
     * @return
     */
//    @Bean
//    public HashedCredentialsMatcher hashedCredentialsMatcher(){
//        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
//        hashedCredentialsMatcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(""));
//        return hashedCredentialsMatcher;
//    }

    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        //myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean(name="simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
        mappings.setProperty("UnauthorizedException","403");
        r.setExceptionMappings(mappings);  // None by default
        r.setDefaultErrorView("error");    // No default
        r.setExceptionAttribute("ex");     // Default is "exception"
        //r.setWarnLogCategory("example.MvcLogger");     // No default
        return r;
    }
}
